﻿//========================================================================
// *作者：海盗猫  主页：ilplay.com
// *脚本：EditorInspectorList
// *描述：EditorInspectorList
// *?2024 HDMCode . All rights reserved.
//* ======================================================================
using HDMCode.FrameEditor;
using HDMCode.UIFrame;
using Unity.CodeEditor;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace HDMCode.UIFrameEditor
{
    public class EditorInspectorList
    {
        /// <summary>
        /// Editor重构脚本
        /// </summary>
        private UIDisplay m_Script;
        
        /// <summary>
        /// 当前Editor序列化的List
        /// </summary>
        public ReorderableList ComponentElementList;
        
        /// <summary>
        /// 基类构造
        /// </summary>
        /// <param name="script">Editor重构脚本</param>
        public EditorInspectorList(UIDisplay script)=>m_Script = script;
        
        /// <summary>
        /// 重构编辑器List界面
        /// </summary>
        /// <param name="serializedObject"></param>
        /// <param name="opElementListSp"></param>
        /// <param name="titleA"></param>
        /// <param name="titleB"></param>
        /// <param name="titleC"></param>
        public void CreateReorderableList(SerializedObject serializedObject,SerializedProperty opElementListSp, string titleA, string titleB, string titleC)
        {
            #region 绘制List高度
            ReorderableList reorderableList = new ReorderableList(serializedObject, opElementListSp)
            {
                elementHeight = EditorGUIUtility.singleLineHeight,
                footerHeight = 30,
            };
            #endregion

            #region 绘制List标题
            reorderableList.drawHeaderCallback = rect =>
            {
                EditorGUILayout head = new EditorGUILayout(rect, rect.width);
                GUIStyle menuStyle = new GUIStyle();
                menuStyle.alignment = TextAnchor.MiddleCenter;
                menuStyle.normal.textColor = Color.gray;
                menuStyle.fontSize = 12;
                Rect iconIndex = new Rect(15, head.IndexRect.y, head.IndexRect.width, head.IndexRect.height);
                Rect tileIndex = new Rect(head.IndexRect.x + iconIndex.x, head.IndexRect.y, head.IndexRect.width, head.IndexRect.height);
                Rect targetRect = new Rect(head.TargetRect.x, head.TargetRect.y, head.TargetRect.width, head.TargetRect.height);
                Rect componentsRect = new Rect(head.ComponentsRect.x, head.ComponentsRect.y, head.ComponentsRect.width, head.ComponentsRect.height);
                GUI.Box(iconIndex, EditorGUIUtility.IconContent("SettingsIcon").image, menuStyle);
                GUI.Label(tileIndex, titleA, menuStyle);
                GUI.Label(targetRect, titleB, menuStyle);
                GUI.Label(componentsRect, titleC, menuStyle);
            };
            #endregion

            #region 绘制List元素
            reorderableList.drawElementCallback = (rect, index, _, _) =>
            {
                rect.height = EditorGUIUtility.singleLineHeight;
                rect.y += EditorGUIUtility.singleLineHeight * 0.1f;

                SerializedProperty element = reorderableList.serializedProperty.GetArrayElementAtIndex(index);
                EditorGUI.PropertyField(rect, element, GUIContent.none);
            };
            #endregion

            #region 绘制List按钮和绑定事件
            reorderableList.drawFooterCallback = rect =>
            {
                ReorderableList list = reorderableList;
                ReorderableList.Defaults rightButtons = ReorderableList.defaultBehaviours;
                ReorderableList.Defaults leftButtons = ReorderableList.defaultBehaviours;
                float elmentWidth = 25;
                float padding = 5;
                Rect rightRect = new Rect(rect.xMax - elmentWidth * 3 - padding, rect.y, (elmentWidth * 3), rect.height);
                Rect leftRect = new Rect(rect.x + padding, rect.y, (elmentWidth * 4), rect.height);

                if (Event.current.type == EventType.Repaint)
                {
                    leftButtons.footerBackground.Draw(leftRect, false, false, false, false);
                    rightButtons.footerBackground.Draw(rightRect, false, false, false, false);
                }

                using (new EditorGUI.DisabledScope())
                {
                    Rect updateRect = new Rect(leftRect.x, leftRect.y, elmentWidth, leftRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("Button Icon").image;
                        if (GUI.Button(updateRect, new GUIContent(icon, "编译脚本"), leftButtons.preButton))
                        {
                            m_Script.transform.AddComponentToString(m_Script.uISingleName).hideFlags= HideFlags.HideInInspector;
                            if (EditorHelper.ContainsSetting(m_Script.uISingleName,out var value))
                            {
                                string outPath = $"{EditorBaseDate.Setting.ScriptPath}/{EditorBaseDate.Setting.Groups[value.Group]}/{value.CreatName}"; 
                                CompileScript(m_Script.name,m_Script.uISingleName,"IUIFrameComponent",outPath);
                            }
                        }
                    }
                }

                using (new EditorGUI.DisabledScope())
                {
                    Rect updateRect = new Rect(leftRect.x + (elmentWidth * 1), leftRect.y, elmentWidth, leftRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("Collab").image;
                        if (GUI.Button(updateRect, new GUIContent(icon, "提交所有列表"), leftButtons.preButton))
                        {
                            RefreshOpElementList(list);
                        }
                    }
                }

                using (new EditorGUI.DisabledScope())
                {
                    Rect updateRect = new Rect(leftRect.x + (elmentWidth * 2), leftRect.y, elmentWidth, leftRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("SceneLoadIn").image;
                        if (GUI.Button(updateRect, new GUIContent(icon, "编辑脚本"), leftButtons.preButton))
                        {
                            if (EditorHelper.GetPathByName(m_Script.uISingleName,out var outPath))
                            {
                                CodeEditor.CurrentEditor.OpenProject(outPath);
                            }
                            else
                            {
                                EditorUtility.DisplayDialog("失败提示：", $"通过编辑器打开脚本失败，请检查资源映射是否成功！\n需要打开的脚本名称：【{m_Script.uISingleName}】\n脚本所在路径:{outPath}", "明白");
                            }
                        }
                    }
                }

                using (new EditorGUI.DisabledScope())
                {
                    Rect updateRect = new Rect(leftRect.x + (elmentWidth * 3), leftRect.y, elmentWidth, leftRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("_Popup").image;
                        if (GUI.Button(updateRect, new GUIContent(icon, "设置中心"), leftButtons.preButton))
                        {
                            Texture winIcon = AssetDatabase.LoadAssetAtPath<Texture>(HDMEditorDate.GUIIconFileAssetsPath + "/WindowIcon.png");
                            HDMEditor.thisWindow = EditorWindow.GetWindow<HDMEditor>();
                            HDMEditor.thisWindow.titleContent = new GUIContent("HDM框架管理系统", winIcon, "HDM框架管理系统");
                            HDMEditor.thisWindow.minSize = new Vector2(600, 600);
                            HDMEditor.thisWindow.maxSize = new Vector2(600, 600);
                            HDMEditor.thisWindow.ShowPopup();
                        }
                    }
                }

                using (new EditorGUI.DisabledScope(list.onCanAddCallback != null && !list.onCanAddCallback(list)))
                {
                    Rect addRect = new Rect(rightRect.x + (elmentWidth * 0), rightRect.y, elmentWidth, rightRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("CollabCreate Icon").image;
                        if (GUI.Button(addRect, new GUIContent(icon, "新增信息到列表"), rightButtons.preButton))
                        {
                            rightButtons.DoAddButton(list);
                        }
                    }
                }
                
                using (new EditorGUI.DisabledScope(list.onCanRemoveCallback != null && !list.onCanRemoveCallback(list)))
                {
                    Rect removeRect = new Rect(rightRect.x + (elmentWidth * 1), rightRect.y, elmentWidth, rightRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("CollabDeleted Icon").image;
                        if (GUI.Button(removeRect, new GUIContent(icon, "移除一条选中的信息"), rightButtons.preButton))
                        {
                            rightButtons.DoRemoveButton(list);
                        }
                    }
                }
                
                //Todo
                // using (new EditorGUI.DisabledScope(list?.index < 0 || list?.index >= list?.count || (list.onCanRemoveCallback != null && !list.onCanRemoveCallback(list))))
                // {
                //     Rect removeRect = new Rect(rightRect.x + (elmentWidth * 1), rightRect.y, elmentWidth, rightRect.height);
                //     {
                //         Texture icon = EditorGUIUtility.IconContent("CollabDeleted Icon").image;
                //         if (GUI.Button(removeRect, new GUIContent(icon, "移除一条选中的信息"), rightButtons.preButton))
                //         {
                //             rightButtons.DoRemoveButton(list);
                //         }
                //     }
                // }
                
                using (new EditorGUI.DisabledScope(list.count <= 0))
                {
                    Rect removeRect = new Rect(rightRect.x + (elmentWidth * 2), rightRect.y, elmentWidth, rightRect.height);
                    {
                        Texture icon = EditorGUIUtility.IconContent("d_CollabExclude Icon").image;
                        if (GUI.Button(removeRect, new GUIContent(icon, "移除所有列表"), rightButtons.preButton))
                        {
                            TrashOpElementList(list);
                        }
                    }
                }
                
                //Todo
                // using (new EditorGUI.DisabledScope())
                // {
                //     Rect removeRect = new Rect(rightRect.x + (elmentWidth * 2), rightRect.y, elmentWidth, rightRect.height);
                //     {
                //         Texture icon = EditorGUIUtility.IconContent("d_CollabExclude Icon").image;
                //         if (GUI.Button(removeRect, new GUIContent(icon, "移除所有列表"), rightButtons.preButton))
                //         {
                //             TrashOpElementList(list);
                //         }
                //     }
                // }
            };
#endregion

            #region 监听List按钮事件
            reorderableList.onAddCallback = AddButonListener;
            reorderableList.onRemoveCallback = RemoveButonListener;
            #endregion

            #region 重写列表的添加按钮事件
            void AddButonListener(ReorderableList list)
            {
                SerializedProperty listDate = list.serializedProperty;
                listDate.arraySize++;
                list.index = listDate.arraySize - 1;
                SerializedProperty newElementSp = listDate.GetArrayElementAtIndex(listDate.arraySize - 1);
                SerializedProperty targetSp = newElementSp.FindPropertyRelative("target");
                targetSp.objectReferenceValue = null;
                newElementSp.serializedObject.ApplyModifiedProperties();
            }
            #endregion

            #region 重写列表的移除按钮事件
            void RemoveButonListener(ReorderableList list)
            {
                SerializedProperty listDate = list.serializedProperty;
                SerializedProperty newElementSp = listDate.GetArrayElementAtIndex(listDate.arraySize - 1);
                newElementSp.DeleteArrayElementAtIndex(listDate.arraySize);
                newElementSp.serializedObject.ApplyModifiedProperties();
            }
            #endregion

            #region 重写列表的清理按钮事件
            void TrashOpElementList(ReorderableList list)
            {
                SerializedProperty listSp = list.serializedProperty;
                listSp.ClearArray();

                listSp.serializedObject.ApplyModifiedProperties();
            }
            #endregion

            #region 重写列表的整理事件
            void RefreshOpElementList(ReorderableList list)
            {
                SerializedProperty listSp = list.serializedProperty;

                //merge components From I to J.
                //将 在I中且不在J中的component加入J，然后将I的Target置为Null。
                for (int i = 1; i < listSp.arraySize; i++)
                {
                    for (int j = 0; j < i; j++)
                    {
                        SerializedProperty elementSpI = listSp.GetArrayElementAtIndex(i);
                        SerializedProperty elementSpJ = listSp.GetArrayElementAtIndex(j);

                        SerializedProperty targetSpI = elementSpI.FindPropertyRelative("target");
                        SerializedProperty targetSpJ = elementSpJ.FindPropertyRelative("target");

                        if (targetSpI.objectReferenceValue == null) { continue; }
                        if (targetSpJ.objectReferenceValue == null) { continue; }

                        if (!targetSpI.objectReferenceValue.Equals(targetSpJ.objectReferenceValue)) { continue; }

                        SerializedProperty componentListSpI = elementSpI.FindPropertyRelative("componentList");
                        SerializedProperty componentListSpJ = elementSpJ.FindPropertyRelative("componentList");

                        for (int m = 0; m < componentListSpI.arraySize; m++)
                        {
                            bool isExistInJ = false;
                            SerializedProperty componentSpIm = componentListSpI.GetArrayElementAtIndex(m);
                            for (int n = 0; n < componentListSpJ.arraySize; n++)
                            {
                                SerializedProperty componentSpJn = componentListSpJ.GetArrayElementAtIndex(n);
                                if (componentSpIm.objectReferenceValue.Equals(componentSpJn.objectReferenceValue))
                                {
                                    isExistInJ = true;
                                    break;
                                }
                            }
                            if (!isExistInJ)
                            {
                                componentListSpJ.InsertArrayElementAtIndex(componentListSpJ.arraySize);
                                componentListSpJ.GetArrayElementAtIndex(componentListSpJ.arraySize - 1).objectReferenceValue = componentSpIm.objectReferenceValue;
                            }
                        }
                        targetSpI.objectReferenceValue = null;
                    }
                }
                //移除所有target为Null 或 componentList 为空的元素
                for (int i = listSp.arraySize - 1; i >= 0; i--)
                {
                    SerializedProperty elementSp = listSp.GetArrayElementAtIndex(i);
                    SerializedProperty targetSp = elementSp.FindPropertyRelative("target");
                    SerializedProperty componentListSp = elementSp.FindPropertyRelative("componentList");

                    if (targetSp.objectReferenceValue == null || componentListSp.arraySize == 0)
                    {
                        //注意：这里删除直接DeleteArrayElementAtIndex即可。（不要先置为null，会报错）
                        listSp.DeleteArrayElementAtIndex(i);
                    }
                }

                listSp.serializedObject.ApplyModifiedProperties();
            }
            #endregion

            #region 编译脚本按钮事件
            void CompileScript(string gameObjectName, string scriptName,string baseClass,string outputFile)
            {
                Debug.Log($"{gameObjectName} \n{scriptName} \n{baseClass} \n{outputFile}");
                DrawScriptTemplate.CreatScript(gameObjectName, scriptName, baseClass, outputFile, m_Script.components);
                AssetDatabase.Refresh();
            }
            #endregion

            ComponentElementList ??= reorderableList;
        }

    }
}
